package main

import (
	"encoding/json"
	"fmt"
	"io"
	"myGo/database"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/gorilla/mux"
	"github.com/natefinch/lumberjack"
	"github.com/rs/cors"
	"github.com/sirupsen/logrus"
)
// 在main.go文件开头添加
type Config struct {
    Port string
    Env  string
}

func getConfig() Config {
    env := os.Getenv("GO_ENV")
    if env == "" {
        env = "development" // 默认为开发环境
    }

    config := Config{
        Env: env,
    }

    // 根据环境设置端口
    switch env {
    case "production":
        config.Port = "8080"
    case "development":
        config.Port = "8079"
    default:
        config.Port = "8079"
    }

    // 如果有环境变量指定端口，则优先使用环境变量的值
    if port := os.Getenv("PORT"); port != "" {
        config.Port = port
    }

    return config
}
var log = logrus.New()

func init() {
	// 配置logrus
	log.SetFormatter(&logrus.JSONFormatter{
		TimestampFormat: time.RFC3339Nano,
		PrettyPrint:     false,
	})

	// 尝试在 /var/log/myapp 创建日志文件
	logPath := "/var/log/myapp/app.log"
	err := os.MkdirAll("/var/log/myapp", 0755)
	if err != nil {
		// 如果失败，则在项目根目录创建 log 文件夹
		currentDir, err := os.Getwd()
		if err != nil {
			log.Fatal("Failed to get current directory:", err)
		}
		logPath = filepath.Join(currentDir, "log", "app.log")
		err = os.MkdirAll(filepath.Dir(logPath), 0755)
		if err != nil {
			log.Fatal("Failed to create log directory:", err)
		}
	}

	// 设置日志输出
	log.SetOutput(io.MultiWriter(
		os.Stdout,
		&lumberjack.Logger{
			Filename:   logPath,
			MaxSize:    50,   // 每个日志文件最大50MB
			MaxBackups: 10,   // 保留10个备份
			MaxAge:     30,   // 保留30天
			Compress:   true, // 压缩旧日志
		},
	))

	log.SetLevel(logrus.InfoLevel)
	log.SetReportCaller(true) // 记录调用位置

	log.Info("Log file path: " + logPath)
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
	log.Info("Received request for home page")
	w.Write([]byte("Welcome to the home page!"))
}

func VisitIPHandler(w http.ResponseWriter, r *http.Request) {
	start := time.Now()
	log.WithFields(logrus.Fields{
		"remoteAddr": r.RemoteAddr,
		"time":       start.Format(time.RFC3339Nano),
	}).Info("Received request")

	ip := r.Header.Get("X-Forwarded-For")
	if ip == "" {
		ip = r.RemoteAddr
	}

	ipInfo := struct {
		Time int64  `json:"time"`
		IP   string `json:"ip"`
	}{
		Time: time.Now().UnixNano() / int64(time.Millisecond),
		IP:   ip,
	}

	w.Header().Set("Content-Type", "application/json")

	err := json.NewEncoder(w).Encode(ipInfo)
	if err != nil {
		log.WithError(err).Error("Error encoding response")
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	duration := time.Since(start)
	log.WithFields(logrus.Fields{
		"duration": fmt.Sprintf("%.3f", float64(duration.Nanoseconds())/1e6),
	}).Info("Request processed")
}

func main() {

    database.InitDB()
    defer database.DB.Close()

    config := getConfig()

    r := mux.NewRouter()
    r.HandleFunc("/", homeHandler)
    r.HandleFunc("/visitip", VisitIPHandler)
    r.HandleFunc("/transaction", addTransactionHandler).Methods("POST")
    r.HandleFunc("/transactions", getTransactionsHandler).Methods("GET")

    c := cors.New(cors.Options{
        AllowedOrigins: []string{"*"},
        AllowedMethods: []string{"GET", "POST", "OPTIONS"},
        AllowedHeaders: []string{"Content-Type", "Authorization"},
    })
	// 在最开始用 fmt 输出醒目的服务信息
	fmt.Printf("\n🚀 Server starting on port %s (%s environment)\n\n", config.Port, config.Env)
    handler := c.Handler(r)
    loggedHandler := logMiddleware(handler)

    serverAddr := ":" + config.Port
    log.WithFields(logrus.Fields{
        "environment": config.Env,
        "port":       config.Port,
    }).Info("Server is starting")
    
    log.Fatal(http.ListenAndServe(serverAddr, loggedHandler))
}

func logMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		log.WithFields(logrus.Fields{
			"method": r.Method,
			"path":   r.URL.Path,
		}).Info("Started request")

		next.ServeHTTP(w, r)

		duration := time.Since(start)
		log.WithFields(logrus.Fields{
			"method":   r.Method,
			"path":     r.URL.Path,
			"duration": fmt.Sprintf("%.3f", float64(duration.Nanoseconds())/1e6),
		}).Info("Completed request")
	})
}

func addTransactionHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var transaction struct {
		UserID      string  `json:"user_id"`
		Amount      float64 `json:"amount"`
		Category    string  `json:"category"`
		Description string  `json:"description"`
	}

	err := json.NewDecoder(r.Body).Decode(&transaction)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// 定义有效的类别
	validCategories := map[string]bool{
		"Food":              true,
		"Daily Necessities": true,
		"Transportation":    true,
		"Social":            true,
		"Housing":           true,
		"Gifts":             true,
		"Communication":     true,
		"Clothing":          true,
		"Entertainment":     true,
		"Beauty":            true,
		"Medical":           true,
		"Taxes":             true,
		"Education":         true,
		"Baby":              true,
		"Pets":              true,
		"Travel":            true,
	}

	// 检查类别是否有效，如果无效则设置为 "Food"
	if !validCategories[transaction.Category] {
		transaction.Category = "Food"
	}

	_, err = database.DB.Exec("INSERT INTO transactions (user_id, amount, category, description) VALUES (?, ?, ?, ?)",
		transaction.UserID, transaction.Amount, transaction.Category, transaction.Description)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(map[string]string{"status": "success"})
}

func getTransactionsHandler(w http.ResponseWriter, r *http.Request) {
	userID := r.URL.Query().Get("user_id")
	if userID == "" {
		log.Error("Missing user_id parameter")
		http.Error(w, "Missing user_id parameter", http.StatusBadRequest)
		return
	}

	log.WithField("user_id", userID).Info("Fetching transactions")

	rows, err := database.DB.Query("SELECT id, amount, category, description, date FROM transactions WHERE user_id = ?", userID)
	if err != nil {
		log.WithError(err).Error("Database query failed")
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	var transactions []map[string]interface{}
	for rows.Next() {
		var id int
		var amount float64
		var category, description string
		var date time.Time
		err := rows.Scan(&id, &amount, &category, &description, &date)
		if err != nil {
			log.WithError(err).Error("Error scanning row")
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
			return
		}
		transactions = append(transactions, map[string]interface{}{
			"id":          id,
			"amount":      amount,
			"category":    category,
			"description": description,
			"date":        date,
		})
	}

	if err = rows.Err(); err != nil {
		log.WithError(err).Error("Error after scanning all rows")
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	log.WithField("count", len(transactions)).Info("Transactions fetched")

	w.Header().Set("Content-Type", "application/json")
	if err := json.NewEncoder(w).Encode(transactions); err != nil {
		log.WithError(err).Error("Error encoding response")
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}
}
